# -*- coding:utf-8 -*-
from framework.interface.abstract_api import AbstractApi
from marshmallow import Schema, fields, validate
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
from collections import namedtuple
from docx import Document
from docx.shared import Cm
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.table import _Cell
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import RGBColor
from docx.shared import Pt
from docx.shared import Inches  # 用于定义英寸单位，可以用于设置缩进
from docx.enum.table import WD_ALIGN_VERTICAL
import requests
from io import BytesIO
import uuid
import os
import subprocess
font_name = '黑体'
font_size_pt = 12  # 小四大概对应12pt
from flask import request
import PyPDF2
import fitz



def Set_cell_border(cell: _Cell, **kwargs):
    """
    设置单元格边框函数
    使用方法:
    Set_cell_border(
        cell,
        top={"sz": 12, "val": "single", "color": "#FF0000", "space": "0"},
        bottom={"sz": 12, "color": "#00FF00", "val": "single"},
        start={"sz": 24, "val": "dashed", "shadow": "true"},
        end={"sz": 12, "val": "dashed"},
    )
    传入参数有cell, 即单元格；top指上边框；bottom指下边框；start指左边框；end指右边框。
    "sz"指线的粗细程度；"val"指线型，比如单线，虚线等；"color"指颜色，颜色编码可百度；
    "space"指间隔，一般不设置，设置的值大于0会导致线错开；"shadow"指边框阴影
    """
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()

    tcBorders = tcPr.first_child_found_in("w:tcBorders")
    if tcBorders is None:
        tcBorders = OxmlElement('w:tcBorders')
        tcPr.append(tcBorders)

    for edge in ('start', 'top', 'end', 'bottom', 'insideH', 'insideV'):
        edge_data = kwargs.get(edge)
        if edge_data:
            tag = 'w:{}'.format(edge)

            element = tcBorders.find(qn(tag))
            if element is None:
                element = OxmlElement(tag)
                tcBorders.append(element)

            for key in ["sz", "val", "color", "space", "shadow"]:
                if key in edge_data:
                    element.set(qn('w:{}'.format(key)), str(edge_data[key]))


def set_vertical_cell_alignment(cell, align="bottom"):
    try:
        align_values = {
            "top": WD_ALIGN_VERTICAL.TOP,
            "center": WD_ALIGN_VERTICAL.CENTER,
            "bottom": WD_ALIGN_VERTICAL.BOTTOM
        }
        cell.vertical_alignment = align_values[align]
    except KeyError:
        raise ValueError("Invalid vertical alignment: {}".format(align))


# 定义一个函数用来添加具有特定样式的标题
def add_custom_heading(document, text, level):
    heading = document.add_heading(level=level)
    run = heading.add_run(text)
    run.font.size = Pt(font_size_pt)  # 设置字体大小为小四
    run.font.name = font_name
    r = run._element
    r.rPr.rFonts.set(qn('w:eastAsia'), font_name)  # 设置字体为黑体
    run.font.color.rgb = RGBColor(0, 0, 0)  # 设置字体颜色为黑色


def doc_model(doc,post_msg, head_table_dict, data_table_dict, imglist):
    for paragraph in doc.paragraphs:
        if paragraph.text == '1.1求解理论':
            blank_run = paragraph.add_run()
            blank_run.add_text("                                                                                       ")
            # 添加新的内容
            content_run = paragraph.add_run(f"(●'◡'●)    {post_msg['理论段1']}")
            content_run.first_line_indent = Inches(0.5)  # 假设每个汉字为0.25英寸，则四个汉字为1英寸
            content_run.font.name = 'Arial'  # 设置字体为Arial
            content_run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体
            content_run.font.size = Pt(12)  # 设置字体大小为12磅
            content_run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色

            paragraphs = doc.add_paragraph()
            # 再次添加一个纯空白的运行来模拟之后的换行（如果需要）
            blank_run2 = paragraphs.add_run()
            blank_run2.add_picture(imglist[3], width=Inches(2.1), height=Inches(2.0))
            paragraphs.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            title_paragraph = doc.add_paragraph(f"""{post_msg['理论段图1']}""")
            title_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            content_runs = doc.add_paragraph()
            content_run = content_runs.add_run(f"(●'◡'●)    {post_msg['理论段2']}")
            content_run.font.name = 'Arial'  # 设置字体为Arial
            content_run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体
            content_run.font.size = Pt(12)  # 设置字体大小为12磅
            content_run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色
            add_custom_heading(doc, '1.2 求解可视化', 2)
            p = doc.add_paragraph()
            p_content = p.add_run(f"""    {post_msg['模型建立过程1']}""")  # 前面空格为4个，表示缩进4个空格
            p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体

            p2 = doc.add_paragraph()
            pic = p2.add_run('')  # 前面空格为4个，表示缩进4个空格
            pic.add_picture(imglist[2], width=Inches(4.0), height=Inches(4.0))
            p2.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            title_paragraph = doc.add_paragraph(f"""{post_msg['可视化图1']}""")
            title_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

            p3 = doc.add_paragraph()
            p_content = p3.add_run(f"    {post_msg['模型建立过程2']}")  # 前面空格为4个，表示缩进4个空格
            p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'),
                                              '宋体')  # 设置中文字体为宋体        p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体

            p4 = doc.add_paragraph()
            pic = p4.add_run('')  # 前面空格为4个，表示缩进4个空格
            pic.add_picture(imglist[0], width=Inches(2.1), height=Inches(2.0))
            pic = p4.add_run('                 ')  # 前面空格为4个，表示缩进4个空格
            pic.add_picture(imglist[1], width=Inches(2.1), height=Inches(2.0))
            p4.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            title_paragraph = doc.add_paragraph(f"    {post_msg['可视化图2']}")
            title_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

            p5 = doc.add_paragraph()
            p_content = p5.add_run(f"""    {post_msg['模型建立过程3']}""")  # 前面空格为4个，表示缩进4个空格
            p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体

            add_custom_heading(doc, '1.3 求解结论', 2)
            # 表格 结果 大致~
            table = doc.add_table(1, len(head_table_dict), style='Normal Table')
            heading_cells = table.rows[0].cells
            for k in range(len(heading_cells)):
                heading_cells[k].text = head_table_dict[k]
                # 将该单元格的垂直对齐设为底对齐
                set_vertical_cell_alignment(heading_cells[k], "center")
                Set_cell_border(
                    heading_cells[k],
                    top={"sz": 15, "color": "#000000", "val": "single"},
                    bottom={"sz": 10, "color": "#000000", "val": "single"},
                    # end={"sz": 6, "color": "#000000", "val": "single"}
                )
            cells = ""
            for data in data_table_dict:
                cells = table.add_row().cells
                for value_index in range(len(data)):
                    cells[value_index].text = data[value_index]

            for k in range(0, len(heading_cells)):
                Set_cell_border(
                    cells[len(cells) - k - 1],
                    bottom={"sz": 12, "color": "#000000", "val": "single"},
                )

                paragraph = heading_cells[k].paragraphs[0]
                p_pr = paragraph._element.get_or_add_pPr()
                spacing = OxmlElement('w:spacing')
                spacing.set(qn('w:before'), str(Pt(0.01)))  # 例如在段落前面增加6磅的间距
                p_pr.insert(0, spacing)
            # 标志上表格的中间表
            p = doc.add_paragraph()
            p_content = p.add_run(f"""    {post_msg['模型建立结果表示例']}""")  # 前面空格为4个，表示缩进4个空格
            p.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体

            # 结论
            p = doc.add_paragraph()
            p_content = p.add_run(f"""    {post_msg['模型建立过程4']}""")  # 前面空格为4个，表示缩进4个空格
            p_content.font.name = 'Arial'  # 设置字体为Arial
            p_content._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 设置中文字体为宋体

            add_custom_heading(doc, '1.4 求解代码', 2)
            table = doc.add_table(2, 1, style='Normal Table')
            heading_cells = table.rows[0].cells
            heading_cells[0].text = "代码部分 ~.py"
            paragraph = heading_cells[0].paragraphs[0]
            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
            p_pr = paragraph._element.get_or_add_pPr()
            spacing = OxmlElement('w:spacing')
            spacing.set(qn('w:before'), str(Pt(0.01)))  # 例如在段落前面增加6磅的间距
            p_pr.insert(0, spacing)
            # 将该单元格的垂直对齐设为底对齐
            set_vertical_cell_alignment(heading_cells[0], "center")

            Set_cell_border(
                heading_cells[0],
                top={"sz": 15, "color": "#000000", "val": "single"},
                bottom={"sz": 15, "color": "#000000", "val": "single"},
                end={"sz": 15, "color": "#000000", "val": "single"},
                start={"sz": 15, "color": "#000000", "val": "single"}
            )

            heading_cells = table.rows[1].cells
            heading_cells[0].text = f"""    {post_msg['模型建立代码']}"""
            paragraph = heading_cells[0].paragraphs[0]
            p_pr = paragraph._element.get_or_add_pPr()
            spacing = OxmlElement('w:spacing')
            spacing.set(qn('w:before'), str(Pt(0.01)))  # 例如在段落前面增加6磅的间距
            p_pr.insert(0, spacing)
            # 将该单元格的垂直对齐设为底对齐
            set_vertical_cell_alignment(heading_cells[0], "center")
            Set_cell_border(
                heading_cells[0],
                top={"sz": 15, "color": "#000000", "val": "single"},
                bottom={"sz": 15, "color": "#000000", "val": "single"},
                end={"sz": 15, "color": "#000000", "val": "single"},
                start={"sz": 15, "color": "#000000", "val": "single"}
            )

def get_pic(keyword):
    # 图片的URL地址
    image_url = f"http://106.53.97.117:7777/v1/get-pic?keyword={keyword}"
    # 从远程位置下载图片
    response = requests.get(image_url).json()
    url=response['result']['result_url']
    print(url,"测试结果")
    response = requests.get(url)
    # 确保请求成功
    if response.status_code == 200:
        print( "测试")
        image_stream = BytesIO(response.content)
    else:
        image_stream=""
    print(image_stream,"测试")
    return image_stream
    #     # 添加图片到文档，指定大小
    #     doc.add_picture(image_stream, width=Inches(4.0), height=Inches(4.0))

class ModelMxqj(AbstractApi):
    """
    接口：ModelMxqj
    文件名输入：model_mxqj
    该接口访问地址为：http://10.10.30.247:9091/v1/model-mxqj
    输入：
    功能：
    输出：
    """

    class PostSchema(Schema):
        part1_1 = fields.Str()
        part1_2 = fields.Str()
        part1_3 = fields.Str()
        part1_4 = fields.Str()
        part1_5 = fields.Str()
        part1_6 = fields.Str()
        part1_7 = fields.Str()

    def handle_post_request(self):
        try:
            output1 = self.get_online_data()
            return output1
        except Exception as e:
            return f"程序异常: {str(e)}", 500

    # 业务1
    def get_online_data(self):
        print(request.get_json()['part1_1'])
        print(request.get_json()['part1_2'])
        print(request.get_json()['part1_3'])
        print(request.get_json()['part1_4'])
        print(request.get_json()['part1_5'])
        print(request.get_json()['part1_6'])
        print(request.get_json()['part1_7'])
        # 采用质谱  总结需要的 图片内容
        url = "http://106.53.97.117:7777/v1/api-g4model"
        headers = {'Content-Type': 'application/json'}
        data1 = {
            "input_text": f"根根据下面文本主题，请输出需要的一个图片关键词，不要有其它输出， 例如： 关于本文SRT飞机起飞示意图 :{request.get_json()['part1_1']}"
        }
        data2 = {
            "input_text": f"根根据下面文本主题，请输出需要的一个图片关键词，不要有其它输出， 例如： 求解曲线结果示意图 :{request.get_json()['part1_3']}"
        }
        data3 = {
            "input_text": f"根根据下面文本主题，请输出需要的一个图片关键词，不要有其它输出 例如： PRC曲线求解结果图 :{request.get_json()['part1_4']}"
        }
        response1 = requests.post(url, headers=headers, json=data1)
        response2 = requests.post(url, headers=headers, json=data2)
        response3 = requests.post(url, headers=headers, json=data3)
        if response1.status_code == 200:
            print("请求成功！")
            # 处理返回的数据
        else:
            print("请求失败，错误码：", response1.status_code)
        if response2.status_code == 200:
            print("请求成功！")
            # 处理返回的数据
        else:
            print("请求失败，错误码：", response2.status_code)
        if response3.status_code == 200:
            print("请求成功！")
            # 处理返回的数据
        else:
            print("请求失败，错误码：", response3.status_code)
        part1 = [
            # 第一段：分析销售量的分布规律及品类间关系
            request.get_json()['part1_1'],
            # 插入图表说明（假设为图2）
            f"""图1：{str(response1.json().get('result')).replace('"','').replace("'","").replace(" ","")[:10]}""",
            # 第二段：预测模型建立及定价策略的制定
            request.get_json()['part1_2'],
        ]
        part2 = [
            request.get_json()['part1_3'],
            f"""图2：{str(response2.json().get('result')).replace('"','').replace("'","").replace(" ","")[:10]}""",
            request.get_json()['part1_4'],
            f"""图3：{str(response3.json().get('result')).replace('"','').replace("'","").replace(" ","")[:10]}"""
        ]
        part3 = [
            # 第一段：蔬菜品类间关联性及销售量分布规律分析
            request.get_json()['part1_5'],

            # 插入图表说明（假设为图4）
            """图4：蔬菜品类间销售量关联性热力图""",

            # 第二段：销售总量与成本加成定价的关系模型建立
            """基于第一问题的分析结果，我们进一步考虑如何同时优化蔬菜品类的日补货总量和成本加成定价策略以实现商超收益最大化。将构建一个动态系统模型来链接销售总量和价格弹性，其中考虑附件中提供的批发价格趋势和近期损耗率数据作为输入变量。利用回归分析和市场需求函数来预测不同定价点对销售量的影响，从而为每个蔬菜品类确定最优的补货数量和定价策略。""",

            # 第三段：考虑空间限制及单品种多样性的补货计划优化
            """受限于商超销售空间和规定的单品数范围，我们需要设计一个组合优化模型来决定最有利的单品补货和定价方案。该模型将采用混合整数规划方法，目标是在满足最小陈列量约束的前提下最大化利润。此外，模型将通过灵活调整可售单品组合应对附件中给出的周期性供应变化，确保7月1日当天的补货策略能高效适应市场需求，推动销售增长并优化收益。""",

            # 插入图表说明（假设为图5）
            """图5：优化后的单品补货策略与定价方案示意图"""
        ]
        # part3 结论 含有表格
        part4 = [
            # 第一段：总结销售量和成本加成定价以及补货决策关系的分析结果
            request.get_json()['part1_6'],
            "表1：这里填写本结论的结果表（开发中~）"]

        # 表格结果示例（根据赛题的要求和格式要求）
        head_table_dict = ['目前开发中', '目前开发中~', '目前开发中）', '目前开发中', '目前开发中）']
        data_table_dict = [
            ['目前开发中', '目前开发中', "目前开发中", "目前开发中", "目前开发中"],
            ['2023-07-02', '目前开发中', "80", "4.50", "90"],
            ['2023-07-03', '目前开发中', "60", "6.00", "65"],
            # ... （以下数据根据模型预测和计算继续添加）
        ]

        part5 = [
            request.get_json()['part1_7'],
        ]
        # 模型的简历与求解
        post_msg = {
            "理论段1": part1[0],
            "理论段图1": part1[1],
            "理论段2": part1[2],
            "模型建立过程1": part2[0],
            "可视化图1": part2[1],
            "模型建立过程2": part2[2],
            "可视化图2": part2[3],
            "模型建立过程3": part3[0],
            "模型建立过程4": part4[0],
            "模型建立代码": part5[0],
            "模型建立结果表示例": part4[1],
        }
        # 根据理论段的图片位置  请求对应的关键字图片
        d1 = get_pic(part1[1])
        d2 = get_pic(part2[1])
        d3 = get_pic(part2[3])
        d4 = get_pic(part2[3])
        img_list = [d1, d2, d3, d4]
        doc = Document(r"m_pj.docx")
        doc_model(doc,post_msg, head_table_dict, data_table_dict, img_list)
        uuid_str = str(uuid.uuid4())
        doc.save(f"./static/{uuid_str}.docx")
        # convert("result.docx", "result.pdf")
        # 构建 unoconv 转换命令
        pdf_path = os.path.join('./static', f"{uuid_str}.pdf")
        docx_path = os.path.join('./static', f"{uuid_str}.docx")
        command = ["unoconv", "-f", "pdf", "-o", pdf_path, docx_path]
        # 使用sudo执行命令
        try:
            subprocess.check_call(command, preexec_fn=os.setuid(0))
        except subprocess.CalledProcessError as e:
            print(f"Error converting file: {e}")
        print("--------------------------节点报错1------------------------------")

        def split_pdf(input_pdf_path, output_folder):
            # 打开PDF文件读取器
            pdf_reader = PyPDF2.PdfReader(input_pdf_path)
            num_pages = len(pdf_reader.pages)
            latex_adr_list = []
            basurl = "http://106.53.97.117:7777/static/"
            # 遍历所有页面并且分别保存为单个PDF
            for page in range(num_pages):
                pdf_writer = PyPDF2.PdfWriter()  # 创建一个PDF写入器
                pdf_writer.add_page(pdf_reader.pages[page])  # 将当前页面添加到写入器
                latex_adr = str(uuid.uuid4())

                # 定义输出的PDF文件名
                output_filename = f"./static/{latex_adr}.pdf"

                # 写入单个页面的PDF
                with open(output_filename, 'wb') as output_pdf:
                    pdf_writer.write(output_pdf)
                latex_adr_list.append(basurl + latex_adr + ".pdf")

            return latex_adr_list
        pdf_url_list = split_pdf(pdf_path, "")
        print("--------------------------节点报错2------------------------------")
        # 对pdf进行切分
        def fitzz_pdf_to_covernt_img(pdf_path, file_name):
            pdf_document = fitz.open(pdf_path)
            for page_number in range(len(pdf_document)):
                if (len(pdf_document) > 1):
                    pass
                else:
                    print(f"-----------------------正在转换中...-----------------")
                    # 获取页面
                    page = pdf_document[page_number]

                    # 渲染页面为图像 - 可选参数设置分辨率，这里设置为300 DPI.
                    pix = page.get_pixmap(matrix=fitz.Matrix(300 / 72, 300 / 72))

                    # 设置输出图片文件名
                    output_image_path = f"./static/{file_name}.png"

                    # 将渲染的页面保存为PNG格式的图片
                    pix.save(output_image_path)
            pdf_document.close()

        for file_name in pdf_url_list:
            file_name=file_name.split("static/")[1]
            if file_name.split(".")[1] == "pdf":
                print("--------------------------节点报错3------------------------------")
                fitzz_pdf_to_covernt_img(f"./static/{file_name}", file_name.split(".")[0])

        return {
            "url_docx":f"http://106.53.97.117:7777/static/{uuid_str}.docx",
            "url_pdf":f"http://106.53.97.117:7777/static/{uuid_str}.pdf",
            "msg_src_list":f"http://106.53.97.117:7777/static/{uuid_str}.pdf",
            "map_msg_pdf_list":pdf_url_list,
            "code":2000
        }
